#pragma once

#include <iostream>
#include <string>
#include <memory>
#include "Socket.hpp"
#include <functional>
#include <jsoncpp/json/json.h>

using namespace SocketModule;

class Request
{
public:
    Request()
    {
    }

    Request(int x, int y, char oper)
        : _x(x), _y(y), _oper(oper)
    {
    }

    std::string Serialize()
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::FastWriter writer;
        std::string s = writer.write(root);
        return s;
    }

    bool Deserialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        bool res = reader.parse(in, root);
        if (res)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt(); //?
        }

        return res;
    }

    ~Request() {}
    int X() { return _x; }
    int Y() { return _y; }
    char Oper() { return _oper; }

private:
    int _x;
    int _y;
    char _oper;
};

class Response
{
public:
    Response()
    {}

    Response(int res, int code)
        : _res(res), _code(code)
    {
    }

    std::string Serialize()
    {
        Json::Value root;
        Json::FastWriter writer;

        root["res"] = _res;
        root["code"] = _code;

        return writer.write(root);
    }

    bool Deserialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        if (reader.parse(in, root))
        {
            _res = root["res"].asInt();
            _code = root["code"].asInt();
            return true;
        }
        return false;
    }

    ~Response()
    {
    }

    void SetResult(int res)
    {
        _res = res;
    }
    void SetCode(int code)
    {
        _code = code;
    }

    void ShowResult()
    {
        std::cout << "the calculation result: " << _res << "[" << _code << "]" << std::endl;
    }


private:
    int _res;  // 运算结果
    int _code; // 退出码
};

const std::string sep = "\r\n";

using func_t = std::function<Response(Request &req)>;

class Protocol
{
public:
    Protocol()
    {}

    Protocol(func_t func)
        : _func(func)
    {}

    // 给序列化的字符串添加报头
    // 构成一条完整的报文
    std::string Encode(const std::string &json_str)
    {
        std::string len = std::to_string(json_str.size());
        return len + sep + json_str + sep;
    }

    // 读取的到信息可能是破碎的，需要人为提供解决方法
    // 示例的例子：服务端通过recv读取的字符串不完整，通过协议解决
    // 也可能是客户端收到服务端的消息（字符串）
    bool Decode(std::string &buffer, std::string *package)
    {
        ssize_t pos = buffer.find(sep);
        // 保证读取到报文报头的长度信息
        if (pos == std::string::npos)
            return false;

        // 报文数据的长度信息
        std::string package_len_str = buffer.substr(0, pos);
        int package_len = std::stoi(package_len_str);

        // 保证完整读到一条报文
        int target_len = package_len + 2 * sep.size() + package_len_str.size();
        if (buffer.size() < target_len)
            return false;

        *package = buffer.substr(pos + sep.size(), package_len);
        buffer.erase(0, target_len);

        return true;
    }

    void GetRequest(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        std::string buffer_queue;
        while (1)
        {
            int n = sock->Recv(&buffer_queue);
            if (n > 0)
            {
                std::string json_package;
                //buffer_queue可能含有多个完整报文，需要循环处理
                while (Decode(buffer_queue, &json_package))
                {
                    //读取到完整的报文，成功输出序列化数据json_package
                    //反序列化
                    Request req;
                    //反序列化失败则跳过
                    if(!req.Deserialize(json_package)) continue;

                    //服务端拿到完整的Request类型的需求
                    //调用回调函数获取结果，返回Response类型的回复
                    Response resp = _func(req);

                    //将要发送给客户端的信回复序列化
                    std::string json_str = resp.Serialize();
                    //添加报头
                    std::string send_str = Encode(json_str);

                    //向客户端发送
                    sock->Send(send_str);
                }

                // std::string json_package;
                // //如果读到的报文不是完整的，那就继续读
                // if(!Decode(bufefr_queue, &json_package))
                //     continue;
            }
            else if (n == 0)
            {
                LOG(LogLevel::INFO) << "client:" << client.StringAddr() << " quit!";
                break;
            }
            else
            {
                LOG(LogLevel::WARNING) << "client:" << client.StringAddr() << ", recv error";
                break;
            }
        }
    }

    bool GetResponse(std::shared_ptr<Socket> &client, std::string &resp_buff, Response *resp)
    {
        while (1)
        {
            int n = client->Recv(&resp_buff);
            if (n > 0)
            {
                std::string json_package;
                while (Decode(resp_buff, &json_package));
                {
                    resp->Deserialize(json_package);
                }
                return true;
            }
            else if (n == 0)
            {
                std::cout << "server quit " << std::endl;
                return false;
            }
            else
            {
                std::cout << "recv error" << std::endl;
                return false;
            }
        }
    }

    std::string BuildRequestString(int x, int y, char oper)
    {
        Request req(x, y, oper);
        std::string json_req = req.Serialize();

        return Encode(json_req);
    }

private:
    func_t _func;
};
